home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / network / manageme / tcpdump-.7 / tcpdump- / tcpdump-richard-1.7 / libpcap-0.0 / pcap-file.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-06-09  |  10.4 KB  |  399 lines

  1. /*
  2.  * Copyright (c) 1993, 1994
  3.  *    The Regents of the University of California.  All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that: (1) source code distributions
  7.  * retain the above copyright notice and this paragraph in its entirety, (2)
  8.  * distributions including binary code include the above copyright notice and
  9.  * this paragraph in its entirety in the documentation or other materials
  10.  * provided with the distribution, and (3) all advertising materials mentioning
  11.  * features or use of this software display the following acknowledgement:
  12.  * ``This product includes software developed by the University of California,
  13.  * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
  14.  * the University nor the names of its contributors may be used to endorse
  15.  * or promote products derived from this software without specific prior
  16.  * written permission.
  17.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
  18.  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
  19.  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  20.  */
  21. #ifndef lint
  22. static char rcsid[] =
  23.     "@(#)$Header: pcap-file.c,v 1.00 94/06/20 19:07:56 leres Exp $ (LBL)";
  24. #endif
  25.  
  26. /*
  27.  * pcap-file.c - supports offline use of tcpdump
  28.  *    Extraction/creation by Jeffrey Mogul, DECWRL
  29.  *    Modified by Steve McCanne, LBL.
  30.  *
  31.  * Used to read saved packets
  32.  * The first record in the file contains saved values for the machine
  33.  * dependent values so we can print the dump file on any architecture.
  34.  */
  35.  
  36. #include <sys/types.h>
  37. #include <sys/time.h>
  38.  
  39. #include <net/bpf.h>
  40.  
  41. #include <errno.h>
  42. #include <memory.h>
  43. #include <stdio.h>
  44. #if __STDC__
  45. #include <stdlib.h>
  46. #endif
  47. #include <unistd.h>
  48.  
  49. #include "pcap-int.h"
  50. #include "order.h"
  51.  
  52.  
  53. /*
  54.  * We use the "receiver-makes-right" approach to byte order,
  55.  * because time is at a premium when we are writing the file.
  56.  * In other words, the pcap_file_header and pcap_pkthdr,
  57.  * records are written in host byte order.
  58.  * Note that the packets are always written in network byte order.
  59.  *
  60.  * ntoh[ls] aren't sufficient because we might need to swap on a big-endian
  61.  * machine (if the file was written in little-end order).
  62.  */
  63.  
  64. #define ERROR_TRUNC        1
  65. #define ERROR_BADVERSION    2
  66. #define ERROR_BADF        3
  67. #define ERROR_EOF        4 /* not really an error, just a status */
  68.  
  69. int link_type[] = 
  70.     { SNOOP_TYPE_OTHER, SNOOP_TYPE_ETHERNET, SNOOP_TYPE_ETHERNET, 
  71.       SNOOP_TYPE_OTHER, SNOOP_TYPE_OTHER, SNOOP_TYPE_OTHER, 
  72.       SNOOP_TYPE_8023, SNOOP_TYPE_OTHER, SNOOP_TYPE_OTHER, 
  73.       SNOOP_TYPE_OTHER, SNOOP_TYPE_FDDI };
  74. int snoop_type[SNOOP_TYPE_UNASSIGNED+1] = 
  75.     { DLT_IEEE802, DLT_IEEE802, DLT_IEEE802, DLT_IEEE802, 
  76.       DLT_EN10MB, DLT_NULL, DLT_NULL, DLT_NULL, DLT_FDDI, DLT_NULL, DLT_NULL };
  77. int snoop_size[SNOOP_TYPE_UNASSIGNED+1] = 
  78.     { DLS_IEEE802, DLS_IEEE802, DLS_IEEE802, DLS_IEEE802, 
  79.       DLS_EN10MB, 0, 0, 0, DLS_FDDI, 0, 0 };
  80.  
  81. static int read_tcpdump_header(struct pcap_file_header *hp, FILE *fp, 
  82.                 pcap_t *p, char *errbuf);
  83. static int next_tcpdump_packet(pcap_t *p, struct pcap_pkthdr *hdr, 
  84.                 u_char *buf, int buflen);
  85. static void swap_tcpdump(struct pcap_file_header *hp);
  86. static int read_snoop_header(struct pcap_file_snoop_header *hp, FILE *fp, 
  87.                 pcap_t *p, char *errbuf);
  88. static int next_snoop_packet(pcap_t *p, struct pcap_snoop_pkthdr *hdr, 
  89.                 u_char *buf, int buflen);
  90. void swap_snoop(struct pcap_file_snoop_header *hp);
  91.  
  92.  
  93. pcap_t *
  94. pcap_open_offline(char *fname, int snaplen, char *errbuf)
  95. {
  96.     register pcap_t *p;
  97.     register FILE *fp;
  98.     struct pcap_file_header tcpdump;
  99.     struct pcap_file_snoop_header snoop;
  100.     int linklen;
  101.  
  102.     p = (pcap_t *)malloc(sizeof(*p));
  103.     if (p == NULL) {
  104.         strcpy(errbuf, "out of swap");
  105.         return NULL;
  106.     }
  107.  
  108. #ifdef notdef
  109.     bzero(p, sizeof(*p));
  110. #else
  111.     memset(p, 0, sizeof(*p));
  112. #endif
  113.     /*
  114.      * Set this field so we don't close stdin in pcap_close!
  115.      */
  116.     p->fd = -1;
  117.  
  118.     if (fname[0] == '-' && fname[1] == '\0')
  119.         fp = stdin;
  120.     else {
  121.         fp = fopen(fname, "r");
  122.         if (fp == NULL) {
  123.             sprintf(errbuf, "%s: %s", fname, pcap_strerror(errno));
  124.             goto bad;
  125.         }
  126.     }
  127.     p->rf.rfile = fp;
  128.  
  129.     if (!read_tcpdump_header(&tcpdump, fp, p, errbuf))
  130.     {
  131.         p->rf.format = FORMAT_TCPDUMP;
  132.         p->tzoff = tcpdump.thiszone;
  133.         p->snapshot = tcpdump.snaplen;
  134.         p->linktype = tcpdump.linktype;
  135.         p->bufsize = tcpdump.snaplen;
  136.         p->rf.version_major = tcpdump.version_major;
  137.         p->rf.version_minor = tcpdump.version_minor;
  138.     }
  139.     else
  140.     if (!read_snoop_header(&snoop, fp, p, errbuf))
  141.     {
  142.         p->rf.format = FORMAT_SNOOP2;
  143.         p->tzoff = 0;
  144.         p->snapshot = snaplen;
  145.         p->linktype = snoop_type[snoop.linktype];
  146.         p->bufsize = snoop_size[snoop.linktype];    /* assume worst case */
  147.         p->rf.version_major = snoop.version;
  148.         p->rf.version_minor = 0;
  149.         if (p->linktype == DLT_NULL || p->bufsize == 0)
  150.         {
  151.             sprintf(errbuf, "unsupported snoop type");
  152.             goto bad;
  153.         }
  154.     }
  155.     else
  156.     {
  157.         sprintf(errbuf, "bad dump file format");
  158.         goto bad;
  159.     }
  160.  
  161.     /* Align link header as required for proper data alignment */
  162.     linklen = 14;                    /* XXX */
  163.     p->rf.base = (u_char *)malloc(p->bufsize + BPF_ALIGNMENT);
  164.     p->buffer = p->rf.base + BPF_ALIGNMENT - (linklen % BPF_ALIGNMENT);
  165.  
  166.     return p;
  167. bad:
  168.     free(p);
  169.     return NULL;
  170. }
  171.  
  172. /*
  173.  * Print out packets stored in the opened file.
  174.  * If cnt > 0, return after 'cnt' packets, otherwise continue until eof.
  175.  */
  176. int
  177. pcap_read_offline(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
  178. {
  179.     struct bpf_insn *fcode = p->fcode.bf_insns;
  180.     int status = 0;
  181.     int n = 0;
  182.  
  183.     while (status == 0) {
  184.         struct pcap_pkthdr tcpdump;
  185.         struct pcap_snoop_pkthdr snoop;
  186.         struct pcap_hdr hdr;
  187.  
  188.         switch (p->rf.format)
  189.         {
  190.         case FORMAT_TCPDUMP:
  191.             status = next_tcpdump_packet(p, &tcpdump, p->buffer, p->bufsize);
  192.             hdr.ts = tcpdump.ts;
  193.             hdr.caplen = tcpdump.caplen;
  194.             hdr.len = tcpdump.len;
  195.             hdr.drops = 0;
  196.             break;
  197.         case FORMAT_SNOOP2:
  198.             status = next_snoop_packet(p, &snoop, p->buffer, p->bufsize);
  199.             hdr.ts.tv_sec = snoop.secs;
  200.             hdr.ts.tv_usec = snoop.usecs;
  201.             hdr.len = snoop.len;
  202.             hdr.caplen = snoop.caplen;
  203.             hdr.drops = snoop.drops;
  204.             break;
  205.         }
  206.         if (status > 0)        /* in case of EOF */
  207.             return 0;
  208.         if (status)        /* in case of some error */
  209.             return -1;
  210.  
  211.         ++p->md.stat.ps_recv;
  212.         if (p->rf.format == FORMAT_SNOOP2)
  213.             p->md.stat.ps_drop = snoop.drops;
  214.  
  215.         if (hdr.caplen > p->snapshot)
  216.             hdr.caplen = p->snapshot;
  217.  
  218.         if (fcode == NULL ||
  219.             bpf_filter(fcode, p->buffer, hdr.len, hdr.caplen)) {
  220.             (*callback)(user, &hdr, p->buffer);
  221.             if (++n >= cnt && cnt > 0)
  222.                 break;
  223.         }
  224.     }
  225.     /*XXX this breaks semantics tcpslice expects */
  226.     return n;
  227. }
  228.  
  229. static int
  230. read_tcpdump_header(struct pcap_file_header *hp, FILE *fp, pcap_t *p, 
  231.                     char *errbuf)
  232. {
  233.     rewind(fp);
  234.     if (fread((char *)hp, sizeof(*hp), 1, fp) != 1) {
  235.         sprintf(errbuf, "fread: %s", pcap_strerror(errno));
  236.         return -1;
  237.     }
  238.     if (hp->magic != TCPDUMP_MAGIC) {
  239.         if (SWAPLONG(hp->magic) != TCPDUMP_MAGIC) {
  240.             sprintf(errbuf, "bad dump file format");
  241.             return -1;
  242.         }
  243.         p->rf.swapped = 1;
  244.         swap_tcpdump(hp);
  245.     }
  246.     if (hp->version_major < PCAP_VERSION_MAJOR) {
  247.         sprintf(errbuf, "archaic file format");
  248.         return -1;
  249.     }
  250.     return 0;
  251. }
  252.  
  253. /*
  254.  * Return the next packet.  Return the header in hdr
  255.  * and the contents in buf.  Return 0 on success, ERROR_EOF if there were
  256.  * no more packets, and ERROR_TRUNC if a partial packet was encountered.
  257.  */
  258. static int
  259. next_tcpdump_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char *buf, int buflen)
  260. {
  261.     FILE *fp = p->rf.rfile;
  262.  
  263.     /* read the stamp */
  264.     if (fread((char *)hdr, sizeof(*hdr), 1, fp) != 1) {
  265.         /* probably an EOF, though could be a truncated packet */
  266.         return 1;
  267.     }
  268.  
  269.     if (p->rf.swapped) {
  270.         /* these were written in opposite byte order */
  271.         hdr->caplen = SWAPLONG(hdr->caplen);
  272.         hdr->len = SWAPLONG(hdr->len);
  273.         hdr->ts.tv_sec = SWAPLONG(hdr->ts.tv_sec);
  274.         hdr->ts.tv_usec = SWAPLONG(hdr->ts.tv_usec);
  275.     }
  276.     /*
  277.      * We interchanged the caplen and len fields at version 2.3,
  278.      * in order to match the bpf header layout.  But unfortunately
  279.      * some files were written with version 2.3 in their headers
  280.      * but without the interchanged fields.
  281.      */
  282.     if (p->rf.version_minor < 3 ||
  283.         (p->rf.version_minor == 3 && hdr->caplen > hdr->len)) {
  284.         int t = hdr->caplen;
  285.         hdr->caplen = hdr->len;
  286.         hdr->len = t;
  287.     }
  288.  
  289.     if (hdr->caplen > buflen) {
  290.         sprintf(p->errbuf, "bad dump file format");
  291.         return -1;
  292.     }
  293.  
  294.     /* read the packet itself */
  295.  
  296.     if (fread((char *)buf, hdr->caplen, 1, fp) != 1) {
  297.         sprintf(p->errbuf, "truncated dump file");
  298.         return -1;
  299.     }
  300.     return 0;
  301. }
  302.  
  303. static void
  304. swap_tcpdump(struct pcap_file_header *hp)
  305. {
  306.     hp->version_major = SWAPSHORT(hp->version_major);
  307.     hp->version_minor = SWAPSHORT(hp->version_minor);
  308.     hp->thiszone = SWAPLONG(hp->thiszone);
  309.     hp->sigfigs = SWAPLONG(hp->sigfigs);
  310.     hp->snaplen = SWAPLONG(hp->snaplen);
  311.     hp->linktype = SWAPLONG(hp->linktype);
  312. }
  313.  
  314. static int read_snoop_header(struct pcap_file_snoop_header *hp, FILE *fp, 
  315.                 pcap_t *p, char *errbuf)
  316. {
  317.     rewind(fp);
  318.     if (fread((char *)hp, sizeof(*hp), 1, fp) != 1) {
  319.         sprintf(errbuf, "fread: %s", pcap_strerror(errno));
  320.         return -1;
  321.     }
  322.     if (memcmp(hp->id, SNOOP_MAGIC, sizeof(hp->id))) {
  323.         sprintf(errbuf, "bad dump file format");
  324.         return -1;
  325.     }
  326.     if (byteorder() != BIG_ENDIAN) {
  327.         p->rf.swapped = 1;
  328.         swap_snoop(hp);
  329.     }
  330.     if (hp->version < PCAP_SNOOP_VERSION) {
  331.         sprintf(errbuf, "archaic file format");
  332.         return -1;
  333.     }
  334.     return 0;
  335. }
  336.  
  337. static int next_snoop_packet(pcap_t *p, struct pcap_snoop_pkthdr *hdr, 
  338.                 u_char *buf, int buflen)
  339. {
  340.     FILE *fp = p->rf.rfile;
  341.  
  342.     /* read the stamp */
  343.     if (fread((char *)hdr, sizeof(*hdr), 1, fp) != 1) {
  344.         /* probably an EOF, though could be a truncated packet */
  345.         return 1;
  346.     }
  347.  
  348.     if (p->rf.swapped) {
  349.         /* these were written in opposite byte order */
  350.         hdr->len = SWAPLONG(hdr->len);
  351.         hdr->caplen = SWAPLONG(hdr->caplen);
  352.         hdr->totlen = SWAPLONG(hdr->totlen);
  353.         hdr->drops = SWAPLONG(hdr->drops);
  354.         hdr->secs = SWAPLONG(hdr->secs);
  355.         hdr->usecs = SWAPLONG(hdr->usecs);
  356.     }
  357.  
  358.     if (hdr->caplen > buflen) {
  359.         sprintf(p->errbuf, "bad dump file format");
  360.         return -1;
  361.     }
  362.  
  363.     /* read the packet itself */
  364.  
  365.     if (fread((char *)buf, hdr->caplen, 1, fp) != 1) {
  366.         sprintf(p->errbuf, "truncated dump file");
  367.         return -1;
  368.     }
  369.  
  370.     if (fseek(fp, hdr->totlen-hdr->caplen-sizeof(*hdr), SEEK_CUR) != 0) {
  371.         return 1;
  372.     }
  373.  
  374.     return 0;
  375. }
  376.  
  377. void
  378. swap_snoop(struct pcap_file_snoop_header *hp)
  379. {
  380.     hp->version = SWAPLONG(hp->version);
  381.     hp->linktype = SWAPLONG(hp->linktype);
  382. }
  383.  
  384. int
  385. pcap_setfilter_offline(pcap_t * p, struct bpf_program *fp)
  386. {
  387.     p->fcode = *fp;
  388.     return 0;
  389. }
  390.  
  391. int
  392. pcap_stats_offline(pcap_t * p, struct pcap_stat *ps)
  393. {
  394.     ps->ps_drop = p->md.stat.ps_drop;
  395.     ps->ps_recv = p->md.stat.ps_recv;
  396.     ps->ps_ifdrop = 0;
  397.     return 0;
  398. }
  399.